﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;

namespace Kit3D.Windows
{
    public class FrameworkElement : UserControl
    {
    }

    public static class Kit3DFrameworkElementExtensionMethods
    {
        private static readonly List<object> _assigned = new List<object>();
        public static void AssignXNames(this DependencyObject obj)
        {
            if (_assigned.Contains(obj))
                return;

            var namedObjects = GetNamedDependencyObjects(obj);
            foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic))
            {
                if (!IsDependencyObjectType(field.FieldType))
                    continue;

                if (field.GetValue(obj) != null)
                    continue;

                var name = field.Name;
                if (namedObjects.ContainsKey(name))
                    field.SetValue(obj, namedObjects[name]);
            }

            _assigned.Add(obj);
        }

        private static Dictionary<string, DependencyObject> GetNamedDependencyObjects(DependencyObject forObj)
        {
            var namedObjects = new Dictionary<string, DependencyObject>();
            AddNamedChildDependencyObjects(forObj, namedObjects);
            return namedObjects;
        }

        private static void AddNamedChildDependencyObjects(DependencyObject onObj, Dictionary<string, DependencyObject> toDictionary)
        {
            foreach (var field in onObj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic))
            {
                foreach (var type in field.FieldType.GetInterfaces())
                {
                    if (type != typeof(IEnumerable))
                        continue;

                    var enumerable = (IEnumerable)field.GetValue(onObj);
                    var enumerator = enumerable.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        var child = enumerator.Current;
                        if (!IsDependencyObjectType(child.GetType()))
                            continue;
                        var childDependencyObject = (DependencyObject)child;
                        AddNamedChildDependencyObjects(childDependencyObject, toDictionary);
                    }
                }

                if (field.FieldType != typeof(DependencyObject) && field.FieldType.IsSubclassOf(typeof(DependencyObject)))
                    continue;

                if (field.DeclaringType == typeof(DependencyObject) && field.Name == "Name")
                    toDictionary[(string)field.GetValue(onObj)] = onObj;
            }
        }

        private static bool IsDependencyObjectType(Type type)
        {
            return (type == typeof(DependencyObject) || type.IsSubclassOf(typeof(DependencyObject)));
        }
    }
}
